如何封装不被嫌弃的组件 SDK
The following article is from 魔术师卡颂 Author 卡颂
你在一家小互联网公司做前端。最近公司发展势头不错,已经有了稳定的商业模式。老板决定尝试付费推广。
老板想策划一个活动玩法。可是公司前端人力有限,不能每个业务都单独开发活动。
于是老板找到了你,希望你封装一个活动SDK
组件供公司几个业务接入。
你心里嘀咕:平时组件写的倒是很多,也写过公共组件,活动组件感觉就是带业务逻辑的公共组件,应该没啥难度吧?
但是你心里没底,怕自己封装的组件SDK
被接入的业务方嫌弃,就去请教公司最资深(发量最少)的前端老卡。
待说明来意,老卡深深啄了一口保温杯里的菊花枸杞茶。
“这封装组件SDK
的门道啊,分为组件设计、开发、接入、上线,待我一一道来”。
组件设计
好的组件设计需要做到职责明确。在设计阶段需要与3个角色明确职责:
与提供数据的服务端明确职责
活动内部需要的数据通常由服务端提供,此时需要明确字段的粒度。
比如:邀请新用户得xxx元奖励
xxx
是变量,通常会作为一个字段。
那么邀请新用户得 元奖励这段文案呢?活动进程中,有没有可能PM
发现这段文案效果不好想修改。
如果前端写死了文案,要修改意味着组件提供方(你)与业务接入方都有重新上线的成本。
所以,如果评估有修改的可能,更好的方式可能是将这段文案下发为类似结构:
data: {
title: "邀请新用户得{{bonus}}元奖励",
params: {
bonus: 123
}
}
与业务接入方明确职责
为了让活动SDK
组件轻量,SDK
内使用的能力(比如:数据请求、登录、错误监控)通常由宿主环境(接入组件的业务)提供。
这类能力分为两类:
运行时业务方能提供的方法
业务方依赖的库提供的能力
其中运行时方法可以作为props
传给SDK
组件,比如登录方法。
库的能力,SDK
需要将其定义为peerDependencies
,比如React
、ReactDOM
。
React
技术栈需要确定SDK
使用的React
版本和业务使用的React
版本需要同时在v16.14
之前或之后,以防JSX
被编译为不同结果(_jsx.createElement
与React.createElement
)
与PM
敲定活动流程
这一步和产品撕过的朋友都懂。
组件开发
完成了职责划分,产出技术文档,接下来就能开始组件开发了。
此时有两点需要注意:
完善的类型提示
使用ts
编写组件,导出类型声明文件,可以极大规范业务方接入,减少接入沟通成本。
错误边界
如果SDK
组件抛出错误,导致接入的页面崩溃了,妥妥的p0
级bug
。
所以,一定要将SDK
的错误catch
在组件内部。
对于React
组件,用ErrorBoundary
包裹是必不可少的。
业务接入
SDK
组件终于开发完了,发布到公司内部npm
平台。
业务方将SDK
以npm
包的形式引入。
此时需要考虑如下问题:
业务接入方以什么模块规范导入(ESM
还是CJS
)?
如果接入方以SSR
的形式在服务端接入组件,可能使用CJS
规范。
CSR
的情况通常使用ESM
。
所以SDK
组件在打包编译时需要输出ESM
、CJS
两种规范的文件。
如果以ESM
导出,需要考虑业务方treeShaking
的需要
如果SDK
会导出几个组件(比如同一个活动组件对不同业务输出不同版本):
// index.tsx
export { default as Base } from './components/Base';
export { default as SDKForA } from './components/SDKForA';
export { default as SDKForB } from './components/SDKForB';
export { default as SDKForC } from './components/SDKForC';
就需要考虑业务方的treeShaking
需要。
当前业界比较通用的方式是:将不同组件编译到不同目录,业务方通过组件目录的形式引用,比如:
// 业务方代码
import SDKForA from 'SDK/dist/modern/components/SDKForA';
其中SDK
为活动组件导出的npm
包。
dist
为编译后产物打包的目录。
modern
为ESM
规范的打包路径,如果要引入CJS
的包,可以将modern
改为node
。
SDKForA
为要引入的组件。
如果业务方使用了babel-plugin-import
,以上写法可以用如下写法替代:
// 业务方代码
import { SDKForA } from 'SDK';
除了js
文件以外,还要考虑业务方对css
文件的编译需要。
所以组件样式文件最好与组件分离,比如将如下路径:
- components
- SDKForA
- index.tsx
- style.less
其中index.tsx
内引入了style.less
修改为:
- components
- SDKForA
- index.tsx
- styles
- SDKForA
- style.less
- style.css
index.tsx
不引入样式文件,由业务方单独引入。
样式产出.css
与.less
两种格式,当业务方需要对样式有进一步编译需求,可以引入.less
,否则直接引入.css
。
业务方在接入时,可以这样接入:
// 业务方代码
import SDKForA from 'SDK/dist/modern/components/SDKForA';
import 'SDK/dist/modern/styles/SDKForA/style.less';
上线
上线后前端就解放啦?NO!
刺激的事儿可都发生在线上~
随着用户量级提升,发生各种bug
的概率也随之提升,主要包括:
接口异常
静态资源加载失败
各种奇奇怪怪的宿主环境造成的报错
关键活动进程的异常
这就需要做好线上监控预警。
如果业务方引入了sentry
,活动SDK
可以为以上case
埋点,并建立对应监控看板。
当错误指标超过阈值,可以随时从被窝里爬起来排查问题。
除了代码的埋点,业务埋点也很重要。某位不知名互联网人说过:
我知道我做的活动会被薅羊毛,但我不知道究竟有多少羊毛被薅了
业务埋点能让你知道。
总结
为了封装一个不被吐槽的SDK
组件,需要做到如下几点:
明确组件职责,知道
SDK
能从宿主环境获得什么能力完善的
ts
声明与错误边界灵活的导出产物,让业务能舒服接入
上线后业务、代码层面的监控
说完这些,老卡又啄了一口保温杯里的菊花枸杞茶,才发现:
茶,早已凉透。
- EOF -
觉得本文对你有帮助?请分享给更多人
推荐关注「前端大全」,提升前端技能
点赞和在看就是最大的支持❤️